package edu.jxufe.nb112.common.web.support.captcha;

import com.octo.captcha.Captcha;
import com.octo.captcha.engine.CaptchaEngine;
import com.octo.captcha.image.ImageCaptcha;
import com.octo.captcha.service.AbstractCaptchaService;
import com.octo.captcha.service.CaptchaServiceException;
import com.octo.captcha.service.captchastore.CaptchaStore;
import com.octo.captcha.service.image.ImageCaptchaService;
import com.octo.captcha.sound.SoundCaptcha;
import com.octo.captcha.text.TextCaptcha;

import javax.sound.sampled.AudioInputStream;
import java.awt.image.BufferedImage;
import java.util.Locale;

/**
 * Created by lvxi on 2018/4/9.
 * Note:
 */
public class JcaptchaService extends AbstractCaptchaService implements ImageCaptchaService {

    JcaptchaService(CaptchaStore captchaStore, CaptchaEngine captchaEngine) {
        super(captchaStore,captchaEngine);
    }
    /**
     * This method must be implemented by sublcasses and : Retrieve the challenge from the captcha Make and return a
     * clone of the challenge Return the clone It has be design in order to let the service dipose the challenge of the
     * captcha after rendering. It should be implemented for all captcha type (@see ImageCaptchaService implementations
     * for exemple)
     *
     * @param captcha
     * @return a Challenge Clone
     */
    @Override
    protected Object getChallengeClone(Captcha captcha) {
        Class captchaClass = captcha.getClass();
        if (ImageCaptcha.class.isAssignableFrom(captchaClass)) {
            BufferedImage challenge = (BufferedImage) captcha.getChallenge();
            BufferedImage clone = new BufferedImage(challenge.getWidth(), challenge.getHeight(), challenge.getType());
            clone.getGraphics().drawImage(challenge, 0, 0, clone.getWidth(), clone.getHeight(), null);
            clone.getGraphics().dispose();
            return clone;
        } else if (SoundCaptcha.class.isAssignableFrom(captchaClass)) {
            AudioInputStream challenge = (AudioInputStream) captcha.getChallenge();
            AudioInputStream clone = new AudioInputStream(challenge, challenge.getFormat(), challenge.getFrameLength());
            return clone;
        } else if (TextCaptcha.class.isAssignableFrom(captchaClass)) {
            return new String(String.valueOf(captcha.getChallenge()));
        } else {
            throw new CaptchaServiceException("Unknown captcha type," +
                    " can't clone challenge captchaClass:'" + captcha.getClass() + "'");
        }
    }

    /**
     * Method to retrive the image challenge corresponding to the given ticket.
     *
     * @param ID the ticket
     * @return the challenge
     * @throws CaptchaServiceException if the ticket is invalid
     */
    public BufferedImage getImageChallengeForID(String ID) throws CaptchaServiceException {
        return (BufferedImage) this.getChallengeForID(ID);
    }

    /**
     * Method to retrive the image challenge corresponding to the given ticket.
     *
     * @param ID     the ticket
     * @param locale
     * @return the challenge
     * @throws CaptchaServiceException if the ticket is invalid
     */
    public BufferedImage getImageChallengeForID(String ID, Locale locale) throws CaptchaServiceException {
        Captcha captcha = engine.getNextCaptcha(locale);
        if(captcha instanceof Jcaptcha){
            Jcaptcha jcaptcha = (Jcaptcha) captcha;
            Object challenge  = getChallengeClone(captcha);
            ((CaptchaCacheStore)this.store).storeAnswer(ID,jcaptcha.getAnswer());
            captcha.disposeChallenge();
            return (BufferedImage) challenge;
        }
        captcha.disposeChallenge();
        return null;
    }

    @Override
    public Boolean validateResponseForID(String ID, Object response) throws CaptchaServiceException {
       String answer = ((CaptchaCacheStore)this.store).getAnswer(ID);
       if(answer==null){
           return false;
       }else {
           ((CaptchaCacheStore)this.store).removeAnswer(ID);
           return Boolean.valueOf(response.equals(answer));
       }
    }

    public boolean checkResponseForID(String ID, Object response){
        String answer = ((CaptchaCacheStore)this.store).getAnswer(ID);
        if(answer==null){
            return false;
        }else {
            return Boolean.valueOf(response.equals(answer));
        }
    }

}
